package repository

import (
	"github.com/gin-gonic/gin"
	"time"
	"yak.admin/src/entity"
	"yak.admin/src/repository"
	"yak.admin/src/service"
	"yak.admin/src/util"
)

type DeviceReportRepository struct {
	Page         int    `form:"page"`
	Pagesize     int    `form:"per-page"`
	Id           int    `form:"id"`
	Province     string `form:"Condition[province]"`
	City         string `form:"Condition[city]"`
	County       string `form:"Condition[county]"`
	IsSuper      bool
	YakLst       string `form:"Condition[yak_lst]"`
	YakLstTxt    string `form:"Condition[yak_lst_txt]"`
	YakLstExt    string `form:"Condition[yak_lst_ext]"`
	Status       int    `form:"Condition[status]"`
	RiskDesc     string `form:"Condition[risk_desc]"`
	RiskAnalysis string `form:"Condition[risk_analysis]"`
	YakDt        string `form:"Condition[yak_dt]"`
	YakDtS       string `form:"Condition[yak_dt_s]"`
	YakDtE       string `form:"Condition[yak_dt_e]"`
	SortReportedAt string `form:"Sort[reported_at]"`
	SortCheckedAt string `form:"Sort[checked_at]"`
	repository.DeviceReportRepository
}

func (repository *DeviceReportRepository) FindReportView(id uint) map[string]interface{} {
	report := entity.DeviceReport{}
	reader := new(service.ReaderQuery).CreateModelQuery(&report).
		WithEQ("id", id).
		WithPreloads([]string{"RiskDescAnnexes", "RiskAnalysisAnnexes"})
	reader.One(&report)
	riskDescLabels := repository.DeviceDescLabels()
	riskAnalysisLabels := repository.DeviceAnalysisLabels()
	// fmt.Println(riskDescLabels)
	return reader.Viewlist(&report, func(item interface{}) map[string]interface{} {
		m := item.(*entity.DeviceReport)
		// annexes := m.DrugAnnexes
		riskDescFnt := func() map[string][]entity.DeviceRiskDescAnnex {
			mm := map[string][]entity.DeviceRiskDescAnnex{}
			for _, v := range m.RiskDescAnnexes {
				label := riskDescLabels[v.Type]
				mm[label] = append(mm[label], v)
			}
			return mm
		}

		riskAnalysisFnt := func() map[string][]entity.DeviceRiskAnalysisAnnex {
			mm := map[string][]entity.DeviceRiskAnalysisAnnex{}
			for _, v := range m.RiskAnalysisAnnexes {
				label := riskAnalysisLabels[v.Type]
				mm[label] = append(mm[label], v)
			}
			return mm
		}

		return map[string]interface{}{
			"id":             m.Id,
			"number":         m.Number,
			"produce_id":     m.ProduceId,
			"produce_number": m.ProduceNumber,
			"produce_name":   m.ProduceName,
			"company_name":   m.CompanyName,
			"reported_at":    reader.AsDatetime(m.ReportedAt),
			"unit":           m.Unit,
			"username":       m.Username,
			"address":        m.Address,
			"phone":          m.Phone,
			"risk_desc":      riskDescFnt(),
			"risk_analysis":  riskAnalysisFnt(),
		}
	})
}

func (repository *DeviceReportRepository) FindReports(c *gin.Context) ([]map[string]interface{}, int64) {
	if err := util.DefaultGetValidParams(c, repository); err != nil {
		return []map[string]interface{}{}, 0
	}

	reader := new(service.ReaderQuery).CreateModelQuery(&entity.DeviceReport{}).
		WithEQ("status", repository.Status).
		// WithPreloads([]string{"User"}).
		WithYakLst(repository.YakLst, repository.YakLstTxt, repository.YakLstExt).
		WithPCC(repository.Province, repository.City, repository.County, repository.IsSuper).
		WithDefaultOrder("reported_at", repository.SortReportedAt, "id", "desc").
		WithPage(repository.Page).WithPageSize(repository.Pagesize)

	var reports []*entity.DeviceReport
	reader.Reader(&reports)
	deviceLabels := repository.DeviceDescLabels()
	analysisLabels := repository.DeviceAnalysisLabels()

	res := reader.Datalist(reports, len(reports), func(index int, item interface{}) map[string]interface{} {
		m := item.(*entity.DeviceReport)
		return map[string]interface{}{
			"_serial":        reader.AsSerial(index),
			"id":             m.Id,
			"number":         m.Number,
			"produce_id":     m.ProduceId,
			"produce_number": m.ProduceNumber,
			"produce_name":   m.ProduceName,
			"company_name":   m.CompanyName,
			"reported_at":    reader.AsDatetime(m.ReportedAt),
			"unit":           m.Unit,
			"username":       m.Username,
			"address":        m.Address,
			"phone":          m.Phone,
			"risk_desc":      reader.AsCheckListString(m.RiskDescRefer, deviceLabels),
			"risk_analysis":  reader.AsCheckListString(m.RiskAnalysisRefer, analysisLabels),
		}
	})

	return res, reader.Count()
}

func (repository *DeviceReportRepository) FindHistoryReports(c *gin.Context, admin entity.Admin) ([]map[string]interface{}, int64) {
	if err := util.DefaultGetValidParams(c, repository); err != nil {
		return []map[string]interface{}{}, 0
	}

	// fmt.Println(repository.YakDt, repository.YakDtS, repository.YakDtE)
	reader := new(service.ReaderQuery).CreateModelQuery(&entity.DeviceReport{}).
		WithEQ("status", repository.Status).
		WithFindInSet("risk_desc_refer", repository.RiskDesc).
		WithFindInSet("risk_analysis_refer", repository.RiskAnalysis).
		WithIN("status", []int{util.IgnoreStatus, util.FollowStatus}).
		WithYakDtIntDate(repository.YakDt, repository.YakDtS, repository.YakDtE, "2006-01-02").
		WithYakLst(repository.YakLst, repository.YakLstTxt, repository.YakLstExt).
		WithEQ("province", repository.Province).
		WithEQ("city", repository.City).
		WithEQ("county", repository.County).
		WithPCC(admin.Province, admin.City, admin.County, repository.IsSuper).
		WithOrder("checked_at", repository.SortCheckedAt).
		WithDefaultOrder("reported_at", repository.SortReportedAt, "id", "desc").
		WithPage(repository.Page).WithPageSize(repository.Pagesize)

	var reports []*entity.DeviceReport
	reader.Reader(&reports)
	deviceLabels := repository.DeviceDescLabels()
	analysisLabels := repository.DeviceAnalysisLabels()
	status := repository.StatusLabels()

	res := reader.Datalist(reports, len(reports), func(index int, item interface{}) map[string]interface{} {
		m := item.(*entity.DeviceReport)
		return map[string]interface{}{
			"_serial":        reader.AsSerial(index),
			"id":             m.Id,
			"number":         m.Number,
			"produce_id":     m.ProduceId,
			"produce_number": m.ProduceNumber,
			"produce_name":   m.ProduceName,
			"company_name":   m.CompanyName,
			"reported_at":    reader.AsDatetime(m.ReportedAt),
			"unit":           m.Unit,
			"username":       m.Username,
			"address":        m.Address,
			"phone":          m.Phone,
			"risk_desc":      reader.AsCheckListString(m.RiskDescRefer, deviceLabels),
			"risk_analysis":  reader.AsCheckListString(m.RiskAnalysisRefer, analysisLabels),
			"status":         m.Status,
			"status_label":   status[m.Status],
			"checked_at":   reader.AsDatetime(m.CheckedAt),
			"comment":      m.Comment,
		}
	})

	return res, reader.Count()
}

func (repository *DeviceReportRepository) FindSummaryReports(c *gin.Context, admin entity.Admin) ([]map[string]interface{}, int64) {
	if err := util.DefaultGetValidParams(c, repository); err != nil {
		return []map[string]interface{}{}, 0
	}

	reader := new(service.ReaderQuery).CreateModelQuery(&entity.DeviceReport{}).
		WithEQ("status", util.FollowStatus).
		WithYakLst(repository.YakLst, repository.YakLstTxt, repository.YakLstExt).
		WithYakDtIntDate(repository.YakDt, repository.YakDtS, repository.YakDtE, "2006-01-02").
		WithEQ("province", repository.Province).
		WithEQ("city", repository.City).
		WithEQ("county", repository.County).
		WithPCC(admin.Province, admin.City, admin.County, admin.IsSuper()).
		WithOrder("checked_at", repository.SortCheckedAt).
		WithDefaultOrder("reported_at", repository.SortReportedAt, "id", "desc").
		WithPage(repository.Page).WithPageSize(repository.Pagesize)

	var reports []*entity.DeviceReport
	reader.Reader(&reports)
	deviceLabels := repository.DeviceDescLabels()
	analysisLabels := repository.DeviceAnalysisLabels()

	res := reader.Datalist(reports, len(reports), func(index int, item interface{}) map[string]interface{} {
		m := item.(*entity.DeviceReport)
		return map[string]interface{}{
			"_serial":        reader.AsSerial(index),
			"id":             m.Id,
			"number":         m.Number,
			"produce_id":     m.ProduceId,
			"produce_number": m.ProduceNumber,
			"produce_name":   m.ProduceName,
			"company_name":   m.CompanyName,
			"reported_at":    reader.AsDatetime(m.ReportedAt),
			"unit":           m.Unit,
			"username":       m.Username,
			"address":        m.Address,
			"phone":          m.Phone,
			"risk_desc":      reader.AsCheckListString(m.RiskDescRefer, deviceLabels),
			"risk_analysis":  reader.AsCheckListString(m.RiskAnalysisRefer, analysisLabels),
			"comment": m.Comment,
		}
	})

	return res, reader.Count()
}

func (repository *DeviceReportRepository) FindHistoryExcel(c *gin.Context, admin entity.Admin) (map[string]interface{}, []map[string]interface{}) {
	if err := util.DefaultGetValidParams(c, repository); err != nil {
		return map[string]interface{}{}, []map[string]interface{}{}
	}

	// fmt.Println(repository.YakDt, repository.YakDtS, repository.YakDtE)
	reader := new(service.ReaderQuery).CreateModelQuery(&entity.DeviceReport{}).
		WithEQ("status", repository.Status).
		WithFindInSet("risk_desc_refer", repository.RiskDesc).
		WithFindInSet("risk_analysis_refer", repository.RiskAnalysis).
		WithIN("status", []int{util.IgnoreStatus, util.FollowStatus}).
		WithYakDtIntDate(repository.YakDt, repository.YakDtS, repository.YakDtE, "2006-01-02").
		WithYakLst(repository.YakLst, repository.YakLstTxt, repository.YakLstExt).
		WithEQ("province", repository.Province).
		WithEQ("city", repository.City).
		WithEQ("county", repository.County).
		WithPCC(admin.Province, admin.City, admin.County, repository.IsSuper).
		WithOrder("checked_at", repository.SortCheckedAt).
		WithDefaultOrder("reported_at", repository.SortReportedAt, "id", "desc").
		WithPage(1).WithPageSize(50000)

	var reports []*entity.DeviceReport
	reader.Reader(&reports)
	deviceLabels := repository.DeviceDescLabels()
	analysisLabels := repository.DeviceAnalysisLabels()
	status := repository.StatusLabels()

	header := map[string]interface{}{
		"_serial":        "序号",
		"number":         "上报编号",
		"produce_id":     "产品名称",
		"produce_number": "产品编号",
		"produce_name":   "产品名称",
		"company_name":   "公司名称",
		"reported_at":    "上报时间",
		"unit":           "上报单位",
		"address":        "所属地区",
		"phone":          "联系电话",
		"risk_desc":      "风险描述",
		"risk_analysis":  "风险分析",
		"checked_at":  "处理时间",
		"status":      "处理状态",
		"comment":     "风险评价",
		"username":       "上报人",
	}

	res := reader.Datalist(reports, len(reports), func(index int, item interface{}) map[string]interface{} {
		m := item.(*entity.DeviceReport)
		return map[string]interface{}{
			"_serial": reader.AsSerial(index),
			//"id":             m.Id,
			"number":         m.Number,
			"produce_id":     m.ProduceId,
			"produce_number": m.ProduceNumber,
			"produce_name":   m.ProduceName,
			"company_name":   m.CompanyName,
			"reported_at":    reader.AsDatetime(m.ReportedAt),
			"unit":           m.Unit,
			"address":        m.Address,
			"phone":          m.Phone,
			"risk_desc":      reader.AsCheckListString(m.RiskDescRefer, deviceLabels),
			"risk_analysis":  reader.AsCheckListString(m.RiskAnalysisRefer, analysisLabels),
			"checked_at":  reader.AsDatetime(m.CheckedAt),
			"status":      status[m.Status],
			"comment":     m.Comment,
			"username":    m.Username,
		}
	})

	return header, res
}

func (repository *DeviceReportRepository) FindSummaryExcel(c *gin.Context, admin entity.Admin) (map[string]interface{}, []map[string]interface{}) {
	if err := util.DefaultGetValidParams(c, repository); err != nil {
		return map[string]interface{}{}, []map[string]interface{}{}
	}

	reader := new(service.ReaderQuery).CreateModelQuery(&entity.DeviceReport{}).
		WithEQ("status", util.FollowStatus).
		WithYakLst(repository.YakLst, repository.YakLstTxt, repository.YakLstExt).
		WithYakDtIntDate(repository.YakDt, repository.YakDtS, repository.YakDtE, "2006-01-02").
		WithEQ("province", repository.Province).
		WithEQ("city", repository.City).
		WithEQ("county", repository.County).
		WithPCC(admin.Province, admin.City, admin.County, admin.IsSuper()).
		WithOrder("checked_at", repository.SortCheckedAt).
		WithDefaultOrder("reported_at", repository.SortReportedAt, "id", "desc").
		WithPage(1).WithPageSize(50000)

	var reports []*entity.DeviceReport
	reader.Reader(&reports)
	deviceLabels := repository.DeviceDescLabels()
	analysisLabels := repository.DeviceAnalysisLabels()

	header := map[string]interface{}{
		"_serial":        "序号",
		"number":         "上报编号",
		"produce_id":     "产品名称",
		"produce_number": "产品编号",
		"produce_name":   "产品名称",
		"company_name":   "公司名称",
		"reported_at":    "上报时间",
		"unit":           "上报单位",
		"address":        "所属地区",
		"phone":          "联系电话",
		"risk_desc":      "风险描述",
		"risk_analysis":  "风险分析",
		"checked_at":  "处理时间",
		"comment":     "风险评价",
		"username":       "上报人",
	}

	res := reader.Datalist(reports, len(reports), func(index int, item interface{}) map[string]interface{} {
		m := item.(*entity.DeviceReport)
		return map[string]interface{}{
			"_serial": reader.AsSerial(index),
			//"id":             m.Id,
			"number":         m.Number,
			"produce_id":     m.ProduceId,
			"produce_number": m.ProduceNumber,
			"produce_name":   m.ProduceName,
			"company_name":   m.CompanyName,
			"reported_at":    reader.AsDatetime(m.ReportedAt),
			"unit":           m.Unit,
			"address":        m.Address,
			"phone":          m.Phone,
			"risk_desc":      reader.AsCheckListString(m.RiskDescRefer, deviceLabels),
			"risk_analysis":  reader.AsCheckListString(m.RiskAnalysisRefer, analysisLabels),
			"checked_at":  reader.AsDatetime(m.CheckedAt),
			"comment":     m.Comment,
			"username":    m.Username,
		}
	})

	return header, res
}

func (repository *DeviceReportRepository) PendingReports(c *gin.Context, admin entity.Admin) int64 {
	timeStr := time.Now().Format("2006-01-02")
	t, _ := time.ParseInLocation("2006-01-02", timeStr, time.Local)
	timeNumber := t.Unix()
	// fmt.Println(t.Format("2006-01-02 15:04:05"))
	return  new(service.ReaderQuery).CreateModelQuery(&entity.DeviceReport{}).
		WithEQ("status", util.PendingStatus).
		WithLTE("reported_at", timeNumber + 86400).
		WithGTE("reported_at", timeNumber).
		WithPCC(admin.Province, admin.City, admin.County, admin.IsSuper()).Count()
}
